/****************************************************************************
 * Copyright (C) 2009-2010 SciTouch LLC
 *
 * This file is part of Indigo toolkit.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/

#include <jni.h>

#include "../cano.h"

#define JNINAME(name) JNICALL Java_com_indigo_Cano_##name

#define CHECK(stmt) if ((*env)->ExceptionOccurred(env)) { stmt; }

void setSession (JNIEnv *env, jobject obj)
{
   jclass cls = (*env)->GetObjectClass(env, obj);
   jfieldID id = (*env)->GetFieldID(env, cls, "_sid", "J");
   jlong sid = (*env)->GetLongField(env, obj, id);
   canoSetSessionId(sid);
}

void throwException (JNIEnv *env, const char *message)
{
   jclass cls = (*env)->FindClass(env, "java/lang/Exception");

   if (cls == NULL)
      return;

   (*env)->ThrowNew(env, cls, message);
   (*env)->DeleteLocalRef(env, cls);
}

void throwCanoException (JNIEnv *env)
{
   throwException(env, canoGetLastError());
}

JNIEXPORT jstring JNINAME(getVersion) (JNIEnv *env, jobject obj)
{
   return (*env)->NewStringUTF(env, canoGetVersion());
}

JNIEXPORT jlong JNINAME(allocSessionId) (JNIEnv *env, jclass cls)
{
   return canoAllocSessionId();
}

JNIEXPORT void JNINAME(releaseSessionId) (JNIEnv *env, jclass cls, jlong id)
{
   canoReleaseSessionId(id);
}

static jstring _canoGetCode (JNIEnv *env, jobject obj,  jstring j_molecule,
                   jstring j_options, int (*getcode)(const char **result))
{
   const char *molecule, *options = NULL, *result = NULL;

   molecule = (*env)->GetStringUTFChars(env, j_molecule, NULL);

   if (molecule == NULL)
   {
      throwException(env, "null molecule given");
      return NULL;
   }

   setSession(env, obj);

   if (!canoSetMolecule(molecule))
   {
      throwCanoException(env);
      return NULL;
   }

   if (j_options != NULL)
   {
      options = (*env)->GetStringUTFChars(env, j_options, NULL);
      if (!canoSetOptions(options))
      {
         throwCanoException(env);
         return NULL;
      }
   }

   if (!getcode(&result))
   {
      throwCanoException(env);
      return NULL;
   }

   (*env)->ReleaseStringUTFChars(env, j_molecule, molecule);
   if (j_options != NULL)
      (*env)->ReleaseStringUTFChars(env, j_options, options);

   return (*env)->NewStringUTF(env, result);
}

JNIEXPORT jstring JNINAME(getCanonicalSmiles) (JNIEnv *env, jobject obj,
                                               jstring j_molecule, jstring j_options)
{
   return _canoGetCode(env, obj, j_molecule, j_options, canoGetCanonicalSmiles);
}

JNIEXPORT jstring JNINAME(getLayeredCode) (JNIEnv *env, jobject obj,
                                     jstring j_molecule, jstring j_options)
{
   return _canoGetCode(env, obj, j_molecule, j_options, canoGetLayeredCode);
}
